package sk.ygor.raynor.client.json;

import com.google.gwt.json.client.JSONValue;

/**
 * Interface for serializing Java class to JSON and JSON to Java classes.
 * Implementation is provided by a registered generator.
 * <p/>
 * User: ygor
 * Date: 2.1.2009
 * Time: 2:58:59
 */
public interface JSONSerializer<T> {

    T deserialize(JSONValue jsonValue);

    JSONValue serialize(T javaObject);

    public static interface HasExternalName {
        @SuppressWarnings({"UnusedDeclaration"})
        // used in generated code
        public String getExternalName();
    }

    /**
     * Interface added to every generated instance of JSONSerializer.
     * <p/>
     * Typical usage is to cast generated instance and invoke configuration methods.
     */
    public static interface Configuration {

        public void setTransformer(Transformer transformer);

    }

    public static interface Transformer {

        @SuppressWarnings({"UnusedDeclaration"})
        // used in generated code
        public String formatExternalClassName(ParametrizedClassName parametrizedClassName);

    }

    @SuppressWarnings({"UnusedDeclaration"})
    // used in generated code as default transformer of generic types
    public static class DefaultTransformer implements Transformer {

        @Override
        public String formatExternalClassName(ParametrizedClassName parametrizedClassName) {
            final StringBuffer sb = new StringBuffer();
            sb.append(transformClassName(parametrizedClassName));
            if (parametrizedClassName.typeParameters.length > 0) {
                sb.append(typeParameterOpening());
                for (int i = 0; i < parametrizedClassName.typeParameters.length; i++) {
                    final ParametrizedClassName typeParameter = parametrizedClassName.typeParameters[i];
                    sb.append(formatExternalClassName(typeParameter));
                    if (i < parametrizedClassName.typeParameters.length - 1) {
                        sb.append(typeParameterSeparator());
                    }
                }
                sb.append(typeParameterClosing());
            }
            return sb.toString();
        }

        protected String transformClassName(ParametrizedClassName parametrizedClassName) {
            return parametrizedClassName.packageName + "." + parametrizedClassName.simpleSourceName;
        }

        protected String typeParameterOpening() {
            return "[";
        }

        protected String typeParameterSeparator() {
            return ",";
        }

        protected String typeParameterClosing() {
            return "]";
        }

    }

    // TODO: cover in test
    public static class SimpleTransformer extends DefaultTransformer {

        protected String transformClassName(ParametrizedClassName parametrizedClassName) {
            return parametrizedClassName.simpleSourceName;
        }

    }

    public static class ParametrizedClassName {
        public final String packageName;
        public final String simpleSourceName;
        public final ParametrizedClassName[] typeParameters;

        public ParametrizedClassName(String packageName, String simpleSourceName, ParametrizedClassName[] typeParameters) {
            this.packageName = packageName;
            this.simpleSourceName = simpleSourceName;
            this.typeParameters = typeParameters;
        }
    }
}
